home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1996 / MacHack 1996.toast / Presentations / Presentations ’92 / PatchWorks Kit / <PatchWorks++> / Patch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-30  |  4.8 KB  |  240 lines  |  [TEXT/KAHL]

  1. /*
  2.     Patch.c
  3.     
  4.     Base class Patch implementation. All patch classes follow the
  5.     patching protocol set up by class Patch. TrapPatch and VectorPatch
  6.     also implemented here.
  7.  
  8.     Part of PatchWorks, the Extension Development Framework.
  9.     
  10.     by Mouse Herrell & Patrick Beard.
  11.     
  12.     Permission is granted to use this source code for any purpose, as long
  13.     as the copyright notice is maintained.
  14.     
  15.     © 1992 Berkeley Systems, Inc.
  16.  */
  17.  
  18. #include "LoMem2.h"
  19. #include "Exceptions.h"
  20. #include "Patch.h"
  21.  
  22. #include <stdio.h>
  23. #include <Memory.h>
  24. #include <Errors.h>
  25. #include <OSUtils.h>
  26. #ifndef __GESTALTEQU__
  27. #include <GestaltEqu.h>
  28. #endif
  29.  
  30. #ifdef THINK_C
  31. #if !__option(a4_globals)
  32. #define GetGlobals() GetA5()
  33. #else
  34. #define GetGlobals() GetA4()
  35. #endif
  36. #endif
  37.  
  38. #ifdef applec
  39. #define GetGlobals() GetA5()
  40. #endif
  41.  
  42. #ifdef __cplusplus
  43. extern "C" {
  44. #endif
  45. void PatchAgent(void);
  46. #ifdef __cplusplus
  47. }
  48. #endif
  49.  
  50. #define cJsrAbsolute 0x4EB9
  51. #define cJmpAbsolute 0x4EF9
  52.  
  53. Patch* Patch::theirList = nil;
  54.  
  55. Patch::Patch()
  56. {
  57.     itsNext = theirList;                            // put us at head of list.
  58.     theirList = this;
  59.  
  60.     itsBehavior = nil;                                // no behaviour installed.
  61.     itsGlobals = GetGlobals();                        // value of our globals register.
  62.     itsInstalled = false;                            // not installed yet.
  63.     itsState = ePatchOn;                            // by default it is enabled.
  64.  
  65.     // allocate our patch stub.
  66.     itsStub = (PatchStub*)NewPtr(sizeof(PatchStub));
  67.     FailNil(itsStub);
  68.     
  69.     // fill in the patch stub.
  70.     itsStub->itsJsrJmp = cJsrAbsolute;                // absolute jsr instruction.
  71.     itsStub->itsPatch = this;                        // pointer to ourself.
  72. }
  73.  
  74. Patch::~Patch()
  75. {
  76.     Patch**    patch;
  77.     
  78.     // disable the patch so it can do no more damage.
  79.     Disable();
  80.     
  81.     // remove us from the patch list.
  82.     patch = &theirList;
  83.     while (*patch && *patch != this)
  84.         patch = &(**patch).itsNext;
  85.     if (*patch)
  86.         *patch = itsNext;
  87.     
  88.     // remove our glue code if we're not installed.
  89.     if (itsStub && !itsInstalled)
  90.         DisposePtr((Ptr)itsStub);
  91. }
  92.  
  93. void Patch::Install()
  94. {
  95.     itsStub->itsAgent = GetAgent();                    // fill in the agent field.
  96.     itsOld = Get();                                    // remember previous patch.
  97.     Set(itsStub);                                    // install new patch.
  98.     itsInstalled = true;                            // note that we are in the patch chain.
  99. }
  100.  
  101. void Patch::RemoveAll()
  102. {
  103.     // remove all patches.
  104.     Patch* patch = theirList;
  105.     while (patch) {
  106.         delete patch;                                // remove from duty.
  107.         patch = patch->itsNext;                        // go to next patch.
  108.     }
  109. }
  110.  
  111. void Patch::Enable() { Switch(ePatchOn); }
  112. void Patch::Disable() { Switch(ePatchOff); }
  113.  
  114. PatchState Patch::Switch(PatchState state)
  115. {
  116.     PatchState oldState = itsState;
  117.     itsState = state;
  118.     
  119.     // only change the internals of the stub if state is changing.
  120.     if (state != oldState) {
  121.         if (state == ePatchOn) {
  122.             itsStub->itsJsrJmp = cJsrAbsolute;
  123.             itsStub->itsAgent = GetAgent();
  124.         } else {
  125.             itsStub->itsJsrJmp = cJmpAbsolute;
  126.             itsStub->itsAgent = itsOld;
  127.         }
  128.         // since we modified some code, flush the instruction & data caches.
  129.         FlushDataCache();
  130.         FlushInstructionCache();
  131.     }
  132.     
  133.     return oldState;
  134. }
  135.  
  136. void* Patch::operator new(size_t n)
  137. {
  138.     void* p = NewPtrClear(n);
  139.     if (!p) throw(memFullErr);
  140.     return p;
  141. }
  142.  
  143. void Patch::operator delete(void* p)
  144. {
  145.     if (p) DisposPtr((Ptr)p);
  146. }
  147.  
  148. PatchProcPtr Patch::Get()
  149. {
  150.     throw (eAbstractErr);
  151. }
  152.  
  153. void Patch::Set(PatchProcPtr proc)
  154. {
  155.     throw (eAbstractErr);
  156. }
  157.  
  158. PatchProcPtr Patch::GetAgent()
  159. {
  160.     // universal agent. this could be replaced if needed, but probably won't be.
  161.     return (PatchProcPtr)&PatchAgent;
  162. }
  163.  
  164. void TrapPatch::InitTrapPatch(PatchProcPtr proc, short trap)
  165. {
  166.     itsBehavior = proc;
  167.     itsTrap = trap;
  168. }
  169.  
  170. PatchProcPtr TrapPatch::Get()
  171. {
  172.     return (PatchProcPtr)NGetTrapAddress(itsTrap, GetTrapType(itsTrap));
  173. }
  174.  
  175. void TrapPatch::Set(PatchProcPtr proc)
  176. {
  177.     NSetTrapAddress((long)proc, itsTrap, GetTrapType(itsTrap));
  178. }
  179.  
  180. void VectorPatch::InitVectorPatch(PatchProcPtr proc, PatchVectorPtr vector)
  181. {
  182.     itsBehavior = proc;
  183.     itsVector = vector;
  184. }
  185.  
  186. PatchProcPtr VectorPatch::Get()
  187. {
  188.     return *itsVector;
  189. }
  190.  
  191. void VectorPatch::Set(PatchProcPtr proc)
  192. {
  193.     *itsVector = proc;
  194. }
  195.  
  196. // Misc. utilities
  197.  
  198. short theOldSR;
  199. VectorPatch* theAddressPatch;
  200. VectorPatch* theBusPatch;
  201.  
  202. void PatchExceptions(void)
  203. {
  204.     theOldSR = SetSR(cSupervisorState + InterruptMask(7));
  205.     
  206.     theAddressPatch = new VectorPatch;
  207.     theAddressPatch->InitVectorPatch((PatchProcPtr)&VException, &JAddressError);
  208.     theAddressPatch->Install();
  209.     
  210.     theBusPatch = new VectorPatch;
  211.     theBusPatch->InitVectorPatch((PatchProcPtr)&VException, &JBusError);
  212.     theBusPatch->Install();
  213. }
  214.  
  215. void RestoreExceptions(void)
  216. {
  217.     delete theAddressPatch;
  218.     delete theBusPatch;
  219.     SetSR(theOldSR);
  220. }
  221.  
  222. void VException(ExceptionPatchFrame frame)
  223. {
  224.     throw (1);
  225. }
  226.  
  227. // routine to call an operating system trap, use frame->old directly to call toolbox routines.
  228.  
  229. void CallOS(register PatchFrame* frame)
  230. {
  231. #ifdef THINK_C
  232.     asm {
  233.         movem.l    frame->rd0, d0-d2/a0/a1        ; load up the registers.
  234.         move.l    frame->old, -(sp)            ; call the os w/o using a register.
  235.         rts
  236.         movem.l    d0-d2/a0/a1, frame->rd0        ; now we have the results.
  237.     }
  238. #endif
  239. }
  240.